// CallBlock.cpp : Defines the entry point for the application.
//

#include <windows.h>
#include <aygshell.h>

#include <snapi.h>
#include <regext.h>

#include "CallBlock.h"

// The window message we'll request the operating system
// to send our main window whenever an incomming phone
// call is received.
#define WM_NEWPHONECALL WM_USER + 1

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))

// Tidies up a phone number by removing non
// essential puncuation characters. The phone
// number is passed in via 'pszPhoneNumber'
// and the filtered phone number is returned
// via the same buffer (it can only become
// shorter due to this filtering process).
static void FilterPhoneNumber(LPTSTR pszPhoneNumber)
{
	LPTSTR pszSrc, pszDest;

	pszSrc = pszDest = pszPhoneNumber;

	// While there are more characters
	// in the phone number
	while (*pszDest)
	{
		// Copy across the next character
		*pszDest = *pszSrc++;

		// Increment the destination pointer,
		// but only if the character we copied
		// isn't one we wanted to filter out.
		if (*pszDest != '('
			&& *pszDest != ')'
			&& *pszDest != '-'
			&& *pszDest != ' ')
			pszDest++;
	}
}

// Message handler for Call Block dialog.
INT_PTR CALLBACK CallBlockDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HREGNOTIFY hNotify = NULL;

    switch (message)
    {
        case WM_INITDIALOG:
			{
                // Resize the dialog to make it cover the full screen
				// and ensure an [X] button is present on the nav bar.
                SHINITDLGINFO shidi;
				SHMENUBARINFO mbi;

                shidi.dwMask = SHIDIM_FLAGS;
                shidi.dwFlags = SHIDIF_CANCELBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
                shidi.hDlg = hDlg;
                SHInitDialog(&shidi);

				// Create a menu bar
                memset(&mbi, 0, sizeof(SHMENUBARINFO));
				mbi.cbSize     = sizeof(SHMENUBARINFO);
				mbi.hwndParent = hDlg;
				mbi.nToolBarId = IDR_MENU;
				mbi.hInstRes   = GetModuleHandle(NULL);
				mbi.dwFlags = SHCMBF_HMENU;
	            SHCreateMenuBar(&mbi);

				// Request to be notified whenever an incomming
				// phone call is detected by the device
				NOTIFICATIONCONDITION condition;
				memset(&condition, 0, sizeof(condition));
				condition.ctComparisonType =  REG_CT_EQUAL;
				condition.dwMask = SN_PHONEINCOMINGCALL_BITMASK;
				condition.TargetValue.dw = SN_PHONEINCOMINGCALL_BITMASK;

				RegistryNotifyWindow(SN_PHONEINCOMINGCALL_ROOT,
					SN_PHONEINCOMINGCALL_PATH,
					SN_PHONEINCOMINGCALL_VALUE,
					hDlg, WM_NEWPHONECALL, 0, &condition, &hNotify);
            }
            return (INT_PTR)TRUE;

		case WM_NEWPHONECALL:
			// Get the phone number associated with the incomming call
			TCHAR szPhoneNumber[2048]; // [CF] - TODO - is there a better number for this???
			RegistryGetString(SN_PHONEINCOMINGCALLERNUMBER_ROOT,
				SN_PHONEINCOMINGCALLERNUMBER_PATH,
				SN_PHONEINCOMINGCALLERNUMBER_VALUE,
				szPhoneNumber, ARRAY_SIZE(szPhoneNumber)); // [CF] - TODO - is last param in bytes or chars?

			FilterPhoneNumber(szPhoneNumber);

			// If it is listed within our list of numbers to block
			if (SendDlgItemMessage(hDlg, IDC_LIST_BLOCKEDNUMBERS, LB_FINDSTRING, 0, (LPARAM)szPhoneNumber) != -1)
			{
				// Simulate the user pressing the 'End' key
				// on their hardware keyboard
                keybd_event(VK_TEND, 0, 0, 0); // Key down
                keybd_event(VK_TEND, 0, KEYEVENTF_KEYUP, 0); // Key up
            }
			return (INT_PTR)TRUE;

        case WM_COMMAND:
            switch (LOWORD(wParam))
			{
				case IDOK:
					// Close the dialog
		            EndDialog(hDlg, LOWORD(wParam));
			        return (INT_PTR)TRUE;

				case IDCANCEL:
					// Minimise the dialog
					ShowWindow(hDlg, SW_MINIMIZE);
					return (INT_PTR)TRUE;

				case IDM_BLOCK:
					// Get the new phone number the user has typed in
					TCHAR szPhoneNumber[2048]; // [CF] - TODO -size this better
					GetDlgItemText(hDlg, IDC_EDIT_PHONENUMBER, szPhoneNumber, ARRAY_SIZE(szPhoneNumber)); // [CF] - TODO - is this bytes or chars?
					
					// Ensure it meets our requirements for what
					// a valid phone number is
					if (_tcslen(szPhoneNumber) == 0)
					{
						MessageBox(hDlg, _T("Phone number cannot be empty."), _T("Alert!"), MB_OK | MB_ICONASTERISK);
				        return FALSE;
					}
            
					if (_tcslen(szPhoneNumber) < 7)
					{
						MessageBox(hDlg, _T("Invalid phone number."), _T("Alert!"), MB_OK | MB_ICONASTERISK);
				        return FALSE;
		            }

					FilterPhoneNumber(szPhoneNumber);

					// Then add it to the list of numbers to block
					// and clear out the textbox so the user can type
					// in another phone number.
					SendDlgItemMessage(hDlg, IDC_LIST_BLOCKEDNUMBERS, LB_ADDSTRING, 0, (LPARAM)szPhoneNumber);
					SetDlgItemText(hDlg, IDC_EDIT_PHONENUMBER, _T(""));
					break;

				case IDM_UNBLOCK:
					{
						// Find the currently selected phone number
						// within the list of numbers to block
						int selectedIndex = SendDlgItemMessage(hDlg, IDC_LIST_BLOCKEDNUMBERS, LB_GETCURSEL, 0, 0);
						if (selectedIndex == -1)
						{
							MessageBox(hDlg, _T("Nothing selected."), _T("Alert!"), MB_OK | MB_ICONASTERISK);
						}
						else
						{
							// Remove it from the list
							SendDlgItemMessage(hDlg, IDC_LIST_BLOCKEDNUMBERS, LB_DELETESTRING, selectedIndex, 0);
						}
					}
					break;

				case IDM_UNBLOCK_ALL:
					// Remove all the numbers from the list of
					// numbers to block
					SendDlgItemMessage(hDlg, IDC_LIST_BLOCKEDNUMBERS, LB_RESETCONTENT, 0, 0);
					break;
            }
            break;

        case WM_CLOSE:
			if (hNotify)
			{
				// Request the operating system to stop sending us
				// notifications for incomming phone calls.
				RegistryCloseNotification(hNotify);
				hNotify = NULL;
			}

			EndDialog(hDlg, message);
            return (INT_PTR)TRUE;
    }

    return (INT_PTR)FALSE;
}

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   int       nCmdShow)
{
	return DialogBox(hInstance, (LPCTSTR)IDD_CALLBLOCK, NULL, CallBlockDialog);
}